home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
AmiTCP30b2.lha
/
src
/
appl
/
napsaterm
/
wimp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-14
|
24KB
|
1,133 lines
/*
* wimp.c --- Intuition interface
*
* Author: ppessi <Pekka.Pessi@hut.fi>
*
* Copyright (c) 1993 Pekka Pessi
*
* Created : Wed Nov 10 11:15:14 1993 ppessi
* Last modified: Fri Feb 4 03:24:24 1994 ppessi
*
* $Log: wimp.c,v $
* Revision 3.4 1994/05/14 14:12:58 ppessi
* Merged changes from Napsaterm 3.5 by R. Knop
*
* Revision 3.3 1994/02/25 02:02:17 ppessi
* Updated some IDCMP macros
*
* Revision 3.2 1994/01/08 08:58:31 ppessi
* Added optional error message requesters;
* fixed menu_move() and menu_execute()
*
* Revision 3.1 94/01/07 22:51:48 ppessi
* Version 3 beta
*
* Revision 2.3 93/11/24 18:31:01 ppessi
* Changed the memory management slightly
*
* Revision 2.2 93/11/18 18:33:24 ppessi
* Changed menu format.
*
* Revision 2.1 93/11/17 15:41:30 ppessi
* Moved the rest of the Intuition code here
* mapwindow() opens the window with OpenWindowTags()
*
* Revision 2.0 93/11/15 03:39:31 ppessi
* Version 2 initial revision
*
*/
RCS_ID_C= "$Id: wimp.c,v 3.4 1994/05/14 14:12:58 ppessi Exp $";
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "nifty.h"
#include "amiga.h"
#include "napsaprefs.h"
#include "nio.h"
#include "display.h"
#include "dispmacros.h"
#include "wimp.h"
#include <assert.h>
#include <stdarg.h>
#include <intuition/intuition.h>
#if USE_PRAGMAS
#include <proto/intuition.h>
#endif
#if USE_INLINE
#include <inline/intuition.h>
#endif
#if USE_CLIB
#include <clib/intuition_protos.h>
#endif
/* This is private */
#ifndef TEKTRONICS /*added RKNOP 940328*/
static struct Window *w = NULL;
#else
struct Window *w = NULL; /*tek4010.c needs this window definition*/
#endif
static struct MsgPort *winport = NULL;
/* We publish only the geometry */
struct geometry wm = { -1, -1, 80, 24 };
#define WM_MINWIDTH 180 /* Minimum height */
static struct {
UWORD left, top, width, height;
} zoom_size =
{ 0, 0, WM_MINWIDTH, 0 };
#define MY_IDCMP_FLAGS \
( IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MENUPICK | \
IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | \
IDCMP_CHANGEWINDOW )
static void parsegeometry(char *gs, struct geometry *gm);
int mapwindow(void);
void unmapwindow(void);
void domouse(struct IntuiMessage * msg);
/*
* display start routine -- sets up display
*/
void dsinit(void)
{
initkeys();
initnations();
initfonts();
/* Set the default geometry */
clearSelection();
disp.visual = np.visual;
disp.blink = np.blink;
disp.invert = np.invert;
disp.style = 0;
disp.curx = disp.cury = disp.winheight = disp.winwidth = 0;
allocate_display(MAXWIDTH, MAXHEIGHT);
parsegeometry(np.geometry, &wm);
if (!mapwindow())
fatalError(MEMORY_ERROR_MSG);
dssizewindow(0, 0, np.col80);
reset_display(0);
redraw_display(1);
}
long dsmask(void)
{
if (w)
return 1 << winport->mp_SigBit;
else
return 0;
}
/*
* Quit
*/
void dsquit(void)
{
ClipClose();
free_display();
if (w)
unmapwindow();
deinitfonts();
deinitkeys();
deinitnations();
}
/*
* Set the geometry as specified
*/
static void parsegeometry(char *gs, struct geometry *gm)
{
long left, top, width, height;
int eaten;
if (gs == NULL || gs[0] == '\0')
return;
eaten = StrToLong(gs, &left);
gs += eaten;
if (eaten < 0 || *gs++ != '/')
return;
eaten = StrToLong(gs, &top);
gs += eaten;
if (eaten < 0 || *gs++ != '/')
return;
eaten = StrToLong(gs, &width);
gs += eaten;
if (eaten < 0 || *gs++ != '/')
return;
if (np.col80)
width = 80;
eaten = StrToLong(gs, &height);
if (eaten < 0 )
return;
/* set user's geometry */
gm->left = left;
gm->top = top;
gm->width = width;
gm->height = height;
}
/*
* Wait a key press
*/
void waitToEnd(void)
{
int class;
struct IntuiMessage *msg;
dscursoroff();
dscursormove(NEXT_LINE, 1);
(void) dsstyle(INVERSE1);
dsputs("** Press any key to exit. **");
dscursoron();
do {
msg = (struct IntuiMessage *)GetMsg(winport);
if (!msg) {
WaitPort(winport);
continue;
}
class = msg->Class;
ReplyMsg(msg);
} while (class != RAWKEY);
}
/*
* DisplayBeep()
*/
void displaybell(void)
{
if (w)
DisplayBeep(w->WScreen);
}
/*
* Event handler for intuition events.
*/
void dspoll(void)
{
struct IntuiMessage *msg;
while (w && (msg = (struct IntuiMessage *)GetMsg(winport))) {
switch(msg->Class) {
case IDCMP_RAWKEY:
dokeys(msg);
break;
case IDCMP_CLOSEWINDOW:
ReplyMsg((struct Message *)msg);
dsquit();
amigaquit();
exit(0);
break;
case IDCMP_NEWSIZE:
ReplyMsg((struct Message *)msg);
redraw_display(1);
break;
case IDCMP_MENUPICK:
domenu(msg);
break;
case IDCMP_MOUSEMOVE:
case IDCMP_MOUSEBUTTONS:
domouse(msg);
break;
#ifdef OWNICONIFY
case IDCMP_GADGETDOWN:
if (DoubleClick(secs, mics, msg->Seconds, msg->Micros)) {
ReplyMsg((struct Message *)msg);
while (msg = (struct IntuiMessage *)GetMsg(w->UserPort))
ReplyMsg((struct Message *)msg);
deiconify();
mapwindow();
}
else {
secs = msg->Seconds; mics = msg->Micros;
ReplyMsg((struct Message *)msg);
}
break;
#endif
default:
ReplyMsg((struct Message *)msg);
}
}
}
/*
* Convert Amiga mouse events to doselection() format
*/
void domouse(struct IntuiMessage *msg)
{
int x, y, count = 0;
x = GETXPOS(msg->MouseX);
y = GETYPOS(msg->MouseY);
BOUNDSCK(x, 0, disp.winwidth);
BOUNDSCK(y, 0, disp.winheight-1);
if (msg->Class == MOUSEBUTTONS) {
if (np.mouse & MOUSE_BOTH) {
register char mousequal = 0x40;
iobuf[0] = ESC;
iobuf[1] = 'M';
if (msg->Code == SELECTUP) {
mousequal |= 1 << 5;
count = 5;
}
if (msg->Code == SELECTDOWN) {
mousequal |= 1 << 4;
count = 5;
}
if (msg->Qualifier & IEQUALIFIER_CAPSLOCK)
mousequal |= 1 << 3;
if (msg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
mousequal |= 1 << 2;
if (msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
mousequal |= 1 << 1;
if (msg->Qualifier & IEQUALIFIER_CONTROL)
mousequal |= 1 << 0;
iobuf[2] = mousequal;
iobuf[3] = ' ' + x;
iobuf[4] = ' ' + y;
}
if (msg->Code == SELECTDOWN) {
ReportMouse(TRUE, w);
doselection(LBDOWN, x, y);
}
if (msg->Code == SELECTUP) {
ReportMouse(FALSE, w);
doselection(LBUP, x, y);
}
} else if (msg->Class == MOUSEMOVE) {
doselection(LMOVE, x, y);
}
ReplyMsg((struct Message *)msg);
if (count)
nwrite(iobuf, count);
}
#include <utility/tagitem.h>
int mapwindow(void)
{
char *pubscname = np.pubscname;
/* Try to find specified public screen */
struct Screen *s = LockPubScreen(pubscname);
/* If not successful, try default */
if (!s && pubscname) {
s = LockPubScreen(pubscname = NULL);
}
/* Give up */
if (!s)
return 0;
#define OPTIONAL(condition, tag) ((condition) ? (tagname), TAG_IGNORE)
zoom_size.top = wm.top < 0 ? s->BarHeight : wm.top;
if (wm.left != -1) {
zoom_size.left = wm.left;
}
zoom_size.height = s->WBorTop + s->Font->ta_YSize + 1;
w = OpenWindowTags(NULL,
WA_PubScreen, s,
WA_InnerWidth, (ULONG)wm.font.w * wm.width,
WA_InnerHeight, (ULONG)wm.font.h * wm.height,
wm.left != -1 ? WA_Left : TAG_IGNORE, (ULONG)wm.left,
WA_Top, zoom_size.top,
np.size_gadget ? WA_SizeGadget : TAG_SKIP, 1L,
np.size_gadget == SIZE_COLUMN ?
WA_SizeBRight : WA_SizeBBottom, 1L,
WA_ScreenTitle, ProgName,
WA_Zoom, &zoom_size,
WA_Flags,
WFLG_SMART_REFRESH | WFLG_CLOSEGADGET
| WFLG_DEPTHGADGET | WFLG_DRAGBAR
| WFLG_NOCAREREFRESH | WFLG_ACTIVATE,
WA_IDCMP, MY_IDCMP_FLAGS,
TAG_DONE );
UnlockPubScreen(NULL, s);
if (!w)
return 0;
winport = w->UserPort;
initmenus();
#if 0
Move(rp, 0, 0);
BltBitMapRastPort(rp->BitMap, 0, 0, rp, w->BorderLeft, w->BorderTop,
w->Width - w->BorderLeft - w->BorderRight,
w->Height - w->BorderTop - w->BorderBottom, WHITE);
#endif
return 1;
}
void unmapwindow(void)
{
if (w) {
wm.left = w->LeftEdge;
wm.top = w->TopEdge;
ClearMenuStrip(w);
deinitmenus();
ModifyIDCMP(w, 0);
CloseWindow(w);
w = NULL;
deinitdrawing();
}
}
/*
* Handle resizing the display
*/
int resize_display(void)
{
register int style;
int xsz, ysz;
int redrawn;
if (!w)
return 0;
wm.xoff = w->BorderLeft;
wm.yoff = w->BorderTop;
wm.x = w->Width - w->BorderRight - w->BorderLeft;
wm.width = xsz = wm.x / wm.font.w;
wm.y = w->Height - w->BorderBottom - w->BorderTop;
wm.height = ysz = wm.y / wm.font.h;
if (np.col80 && xsz > 80)
xsz = 80;
if (xsz < MINWIDTH || ysz < MINHEIGHT) {
deinitdrawing();
showbanner(w->RPort, "Make me BIGGER");
return 0;
}
redrawn = initdrawing(w->RPort);
if (!redrawn && xsz == disp.winwidth && ysz == disp.winheight) {
return redrawn;
}
BOUNDSCK(xsz, MINWIDTH, disp.maxwidth);
BOUNDSCK(ysz, MINHEIGHT, disp.maxheight);
if ((disp.scrolltop == 0 && disp.scrollbot == disp.winheight-1) ||
disp.scrollbot >= ysz)
disp.scrollbot = ysz-1;
if (disp.scrolltop >= ysz)
disp.scrolltop = 0;
if (disp.cury >= ysz) {
deinitdrawing();
dsscroll(0, disp.winheight, disp.cury - ysz + 1);
initdrawing(w->RPort);
disp.cury = ysz - 1;
}
disp.winwidth = xsz, disp.winheight = ysz;
dssizewindow(xsz, ysz, 0);
DSRESIZE();
niosize(ysz, xsz, wm.x, wm.y);
setnewtitle();
return 1;
}
/*
* Set window size according the given display size
*/
void dssizewindow(int width, int height, int widthflag)
{
if (!w) {
return;
} else {
int ow = w->Width, nw;
int oh = w->Height, nh;
if (width)
nw = MIN(width * wm.font.w + w->BorderLeft + w->BorderRight,
w->WScreen->Width);
else
nw = ow;
if (height)
nh = MIN(height * wm.font.h + w->BorderTop + w->BorderBottom,
w->WScreen->Height);
else
nh = oh;
if ((nw-ow) || (nh-oh)) {
SizeWindow(w, nw - ow, nh - oh);
#if 0
/* wait for resize message */
WaitPort(w->UserPort);
#endif
}
if (np.col80) {
WindowLimits(w, nw, zoom_size.height, nw, 0);
} else {
WindowLimits(w, zoom_size.width, zoom_size.height,
MAXWIDTH * wm.font.w, MAXHEIGHT * wm.font.h);
}
}
}
/*
* Handle window and screen titles
*/
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
void setnewtitle(void)
{
static char Title[MAXHOSTNAMELEN + 16];
int rows = wm.height, cols = wm.width;
if (np.title)
strncpy(Title, np.title, sizeof(Title));
else
strcpy(Title, ProgName);
strncat(Title, " (", sizeof(Title));
strncat(Title, itos(cols), sizeof(Title));
strncat(Title, " x ", sizeof(Title));
strncat(Title, itos(rows), sizeof(Title));
strncat(Title, ")", sizeof(Title));
if (w)
SetWindowTitles(w, Title, (UBYTE*)ProgName);
}
#include <errno.h>
/*
* Print the IO error messages
*/
void perror(const char *banner)
{
const char *error = strerror(errno);
if (started_from_workbench && IntuitionBase != NULL) {
struct EasyStruct libraryES;
libraryES.es_StructSize = sizeof(libraryES);
libraryES.es_Flags = 0;
libraryES.es_Title = ProgName;
libraryES.es_TextFormat = "%s: %s";
libraryES.es_GadgetFormat = "Continue";
EasyRequest(w, &libraryES, NULL, banner, error);
} else {
Printf("%s: %s\n", banner, error);
}
}
void herror(const char *banner, const char *error)
{
if (started_from_workbench && IntuitionBase != NULL) {
struct EasyStruct libraryES;
libraryES.es_StructSize = sizeof(libraryES);
libraryES.es_Flags = 0;
libraryES.es_Title = ProgName;
libraryES.es_TextFormat = "%s: %s";
libraryES.es_GadgetFormat = "Continue";
EasyRequest(w, &libraryES, NULL, banner, error);
} else {
Printf("%s: %s\n", banner, error);
}
}
/*
* Print the error message and die
*/
void fatalError(const char *s, ...)
{
va_list va;
va_start(va, s);
if (started_from_workbench && IntuitionBase != NULL) {
struct EasyStruct libraryES;
libraryES.es_StructSize = sizeof(libraryES);
libraryES.es_Flags = 0;
libraryES.es_Title = ProgName;
libraryES.es_TextFormat = s;
libraryES.es_GadgetFormat = "Quit";
EasyRequestArgs(w, &libraryES, NULL, va);
} else {
PutStr(PROGNAME ": ");
VPrintf(s, (LONG *)va);
va_end(va);
PutStr("\n");
}
dsquit();
amigaquit();
exit(130);
}
/*
* Menus
*/
#define MENU_CMD 0
#define MENU_EDIT 1
#define MENU_SETUP 2
#if 0
#define MENU_NATIONAL 3
static struct Menu nationalmenu = {
NULL, 120, 0, 55, 10, MENUENABLED, (BYTE *)"National", 0, 0, 0, 0, 0,
};
#endif
static struct Menu setupmenu = {
NULL, 55, 0, 45, 10, MENUENABLED, (BYTE *)"Setup", 0, 0, 0, 0, 0,
};
static struct Menu editmenu = {
&setupmenu, 2, 0, 45, 10, MENUENABLED, (BYTE *)"Edit", 0, 0, 0, 0, 0,
};
static struct Menu cmdmenu = {
&editmenu, 2, 0, 45, 10, MENUENABLED, (BYTE *)"Command", 0, 0, 0, 0, 0,
};
/* These macros use some fudge factors to make manus look good */
/* 9 is space between menus in the menu bar */
#define MENUWIDTH(menu) (9 + \
TextLength(&(w->WScreen->RastPort), (menu).MenuName, strlen((menu).MenuName)))
/* 35 is the approximate size of the "A" symbol in the menus */
#define CMDWIDTH(cmd) (35 + \
TextLength(&(w->WScreen->RastPort), &(cmd), 1))
#define ITEMWIDTH(str) \
TextLength(&(w->WScreen->RastPort), (UBYTE*)(str), strlen(str));
/*
* Menu callback utility functions
*/
static void menu_state(UBYTE mnum, UBYTE inum, UBYTE subnum, UBYTE enabled)
{
struct Menu *menu;
struct MenuItem *item;
for (menu = &cmdmenu; mnum > 0; mnum--)
menu = menu->NextMenu;
for (item = menu->FirstItem; inum > 0; inum--)
item = item->NextItem;
/* subnum is ignored for now */
assert(subnum == NOSUB);
if (enabled)
item->Flags |= ITEMENABLED;
else
item->Flags &= ~ITEMENABLED;
}
/*
* Menu callback routines
*/
void menu_move(UBYTE mnum, UBYTE item, UBYTE sub)
{
if (isSelection()) {
char *selstring, *temp;
if ((temp = selstring = grabSelection())) {
while (*temp++)
;
nwrite(selstring, temp - selstring - 1);
FreeVec(selstring);
}
}
}
void menu_execute(UBYTE mnum, UBYTE item, UBYTE sub)
{
if (isSelection()) {
menu_move(mnum, item, sub);
nwrite("\n", 1);
}
}
void menu_copy(UBYTE mnum, UBYTE item, UBYTE sub)
{
if (isSelection()) {
char *selstring = grabSelection();
ClipCut(selstring);
FreeVec(selstring);
}
}
void menu_paste(UBYTE mnum, UBYTE item, UBYTE sub)
{
nwrite(iobuf, ClipPaste(iobuf, sizeof(iobuf)));
}
void menu_clear(UBYTE mnum, UBYTE item, UBYTE sub)
{
dscursoroff();
if (disp.cury) {
dsscroll(0, disp.winheight, disp.cury);
disp.cury = 0;
}
dsfunction(ERASETO_EOS);
dscursoron();
}
#ifdef TEKTRONICS /*added RKNOP 940328*/
void menu_totek(UBYTE mnum,UBYTE item,UBYTE sub)
{
vt100_tek();
}
void menu_tovt100(UBYTE mnum,UBYTE item,UBYTE sub)
{
tek_vt100();
}
#endif
void menu_reset(UBYTE mnum, UBYTE item, UBYTE sub)
{
dscursoroff();
dsfunction(RESET_DISPLAY);
dscursoron();
}
void menu_flush(UBYTE mnum, UBYTE item, UBYTE sub)
{
nioctl(NIO_FLUSH, 0, 0);
}
void menu_break(UBYTE mnum, UBYTE item, UBYTE sub)
{
nioctl(NIO_BREAK, 0, 0);
}
#ifdef OWNICONIFY
void menu_iconify(UBYTE mnum, UBYTE item, UBYTE sub)
{
unmapwindow();
iconify();
}
#endif
/*
* Note: listen must be just before unlisten in its menu!
*/
void menu_listen(UBYTE mnum, UBYTE item, UBYTE sub)
{
menu_state(mnum, item, sub, FALSE);
/* Enable UnListen if nabort() is successful */
if (!nabort())
menu_state(mnum, item + 1, sub, TRUE);
else
/* otherwise, re-enable us */
menu_state(mnum, item, sub, TRUE);
ResetMenuStrip(w, &cmdmenu);
}
void menu_unlisten(UBYTE mnum, UBYTE item, UBYTE sub)
{
menu_state(mnum, item, sub, FALSE);
/* Enable Listen if nabort() is successful */
if (nabort())
menu_state(mnum, item - 1, sub, TRUE);
else
/* otherwise, re-enable us */
menu_state(mnum, item, sub, TRUE);
ResetMenuStrip(w, &cmdmenu);
}
void menu_quit(UBYTE mnum, UBYTE item, UBYTE sub)
{
dsquit();
amigaquit();
exit(0);
}
/*
* Callback routines for setup menu -- prototypes on <napsaprefs.h>
*/
void change_cursor(int mode)
{
dscursoroff();
disp.visual = mode;
dscursoron();
}
/* added RKNOP 940328 */
void change_ansi_LNM(int on)
{ np.ansi_LNM=on;
}
/* end added RKNOP 940328 */
void change_invert(int on)
{
dsinvert(on ? INVERT_ON : INVERT_OFF);
}
void change_mode80(int on)
{
if (on)
dssizewindow(80, 0, 1);
else
WindowLimits(w, 0, 0, -1, -1);
#if 0
redraw_display(1);
#endif
}
void change_national(int national)
{
(void) redraw_display(0);
}
void change_nation(int nation)
{
setnation(nation);
if (np.national == NAT_7BIT)
(void) redraw_display(0);
}
/*
* The text of the menu, callback function and the HotKey for it.
*/
struct menudef {
char *text;
void (*call_f)(UBYTE mnum, UBYTE item, UBYTE sub);
char com;
unsigned ser : 1; /* active only with serial */
unsigned off : 1; /* not active by default */
};
static struct menudef cmd_items[] =
{
{ "Clear Screen", menu_clear, 'S', },
#ifdef TEKTRONICS /*added RKNOP 940328*/
{ "To Tek4010", menu_totek, 'G', },
{ "To VT102", menu_tovt100, 'T', },
#endif
{ "Soft Reset", menu_reset, 'R', },
{ "Flush", menu_flush, 'F', },
{ "Break", menu_break, 'B', 1, },
{ "Listen", menu_listen, 'L', 1, 1, },
{ "Unlisten", menu_unlisten, 'U', 1, },
{ "Quit", menu_quit, 'Q', },
{ NULL, },
};
static struct menudef edit_items[] =
{
{ "Copy", menu_copy, 'C', },
{ "Paste", menu_paste, 'V', },
{ "Move", menu_move, 'M', },
{ "Execute", menu_execute, 'E', },
{ NULL, },
};
/*
* Initialize a menu item
*/
static struct MenuItem *inititem(struct MenuItem **first,
struct MenuItem *last,
const char *str, char com)
{
struct IntuiText *it;
struct MenuItem *mi;
/*
* Templates
*/
static struct MenuItem protoitem = {
NULL, 0, 0, 0, 0, HIGHCOMP | ITEMTEXT | ITEMENABLED,
0, NULL, NULL, 0, NULL, 0
};
static struct IntuiText prototext = {
0, 1, JAM2, 0, 0, NULL, NULL, NULL
};
mi = (struct MenuItem *)
AllocVec(sizeof(*mi) + sizeof(*it), MEMF_PUBLIC);
if (last)
last->NextItem = mi;
else
*first = mi;
if (mi == NULL) {
fatalError(MEMORY_ERROR_MSG);
}
it = (struct IntuiText *)(mi + 1);
*mi = protoitem; *it = prototext;
mi->TopEdge = last ? last->TopEdge + w->WScreen->RastPort.TxHeight + 1 : 0;
mi->Height = w->WScreen->RastPort.TxHeight + 1;
mi->Width = ITEMWIDTH(str);
mi->ItemFill = (APTR)it;
if (com) {
mi->Command = com;
mi->Flags |= COMMSEQ;
mi->Width += CMDWIDTH(mi->Command);
}
it->TopEdge = 1;
it->IText = (UBYTE *)str;
return mi;
}
static void initmenu(struct Menu *menu, struct menudef newmenu[])
{
struct MenuItem *li = NULL;
long width = 0;
menu->Width = MENUWIDTH(*menu);
for (; newmenu->text; newmenu++) {
li = inititem(&menu->FirstItem, li, newmenu->text, newmenu->com);
width = (li->Width > width) ? li->Width : width;
if (iotype != serial && newmenu->ser || newmenu->off) {
li->Flags &= ~ITEMENABLED;
}
}
for (li = menu->FirstItem; li; li = li->NextItem)
li->Width = width;
}
/*
* Initialize and show menus
*/
void initmenus(void)
{
if (!cmdmenu.FirstItem) {
long width, me;
const char *mtxt;
struct MenuItem *li;
initmenu(&cmdmenu, cmd_items);
initmenu(&editmenu, edit_items);
editmenu.LeftEdge = cmdmenu.LeftEdge + cmdmenu.Width;
setupmenu.Width = MENUWIDTH(setupmenu);
setupmenu.LeftEdge = editmenu.LeftEdge + editmenu.Width;
for (me = 0, li = NULL, width = 0; mtxt = setup_items[me].title; me++) {
li = inititem(&setupmenu.FirstItem, li, mtxt, 0);
if (mtxt = setup_items[me].texts) {
int subi, val = getsetup(me);
struct MenuItem *si = NULL;
for (subi = 0; *mtxt; subi++) {
si = inititem(&li->SubItem, si, mtxt, 0);
si->MutualExclude = ~(1<<subi);
si->Flags |= CHECKIT;
if (subi == val)
si->Flags |= CHECKED;
while (*mtxt++)
;
si->Width += CHECKWIDTH;
((struct IntuiText *)si->ItemFill)->LeftEdge = CHECKWIDTH;
}
} else {
li->Flags |= CHECKIT | MENUTOGGLE;
if (getsetup(me))
li->Flags |= CHECKED;
li->Width += CHECKWIDTH;
((struct IntuiText *)li->ItemFill)->LeftEdge = CHECKWIDTH;
}
width = (li->Width > width) ? li->Width : width;
}
for (li = setupmenu.FirstItem; li; li = li->NextItem) {
struct MenuItem *si;
int subwidth = width / 2;
for (si = li->SubItem; si; si = si->NextItem) {
si->TopEdge += w->WScreen->RastPort.TxHeight + 2;
si->LeftEdge = setupmenu.Width;
subwidth = (si->Width > subwidth) ? si->Width : subwidth;
}
for (si = li->SubItem; si; si = si->NextItem) {
si->Width = subwidth;
}
li->Width = width;
}
#if 0
nationalmenu.Width = MENUWIDTH(nationalmenu);
for (me = 0, li = NULL, width = 0; mtxt = getnationname(me); me++) {
li = inititem(&nationalmenu.FirstItem, li, mtxt, 0);
li->MutualExclude = ~(1<<me);
li->Flags |= CHECKIT;
if (me == getnationnumber())
li->Flags |= CHECKED;
width = (li->Width > width) ? li->Width : width;
}
width += CHECKWIDTH;
for (li = nationalmenu.FirstItem; li; li=li->NextItem) {
li->Width = width;
((struct IntuiText *)li->ItemFill)->LeftEdge = CHECKWIDTH;
}
#endif
}
SetMenuStrip(w, &cmdmenu);
}
void deinitmenus(void)
{
struct Menu *menu;
struct MenuItem *mi, *ni, *si, *sni;
for (menu = &cmdmenu; menu; menu = menu->NextMenu) {
for (mi = menu->FirstItem; mi; mi = ni) {
ni = mi->NextItem;
for (si = mi->SubItem; si; si = sni) {
sni = si->NextItem;
FreeVec(si), si = NULL;
}
FreeVec(mi), mi = NULL;
}
menu->FirstItem = NULL;
}
}
/*
* Setup menu dispatcher
*/
static void domenu_setup(register UBYTE which, register BYTE sub)
{
register BYTE new, cleared = 0;
struct MenuItem *mi, *si;
/* We will get no extra events for extended selection */
for (which = 0, mi = setupmenu.FirstItem; mi; mi = mi->NextItem, which++) {
if (si = mi->SubItem) {
for (sub = 0; si; sub++, si = si->NextItem) {
if ((si->Flags & CHECKED) == CHECKED)
break;
}
/* None was checked.. */
if (!si)
sub = -1;
} else {
sub = (mi->Flags & CHECKED) == CHECKED;
}
new = changesetup(which, sub);
if (sub != new) {
if (!cleared)
ClearMenuStrip(w);
cleared = 1;
if (si = mi->SubItem) {
/* Check an item in submenu */
for (sub = 0; si; sub++, si = si->NextItem) {
if (sub == new)
si->Flags |= CHECKED;
else
si->Flags &= ~CHECKED;
}
} else {
if (new)
mi->Flags |= CHECKED;
else
mi->Flags &= ~CHECKED;
}
}
}
/*
* Redraw menu
*/
if (cleared)
ResetMenuStrip(w, &cmdmenu);
}
/*
* National menu dispatcher
*/
static void domenu_nation(register UBYTE nation, register UBYTE sub)
{
setnation(nation);
(void) redraw_display(0);
}
/*
* Menu dispatcher
*/
void domenu(register struct IntuiMessage *msg)
{
register ULONG code = msg->Code;
register UBYTE mnum = MENUNUM(code);
register UBYTE item = ITEMNUM(code);
register UBYTE sub = SUBNUM(code);
ReplyMsg(msg), msg = NULL;
/* so we know that item is always valid */
if (code == MENUNULL || mnum == NOMENU || item == NOITEM)
return;
switch (mnum) {
case MENU_CMD:
if (cmd_items[item].call_f)
cmd_items[item].call_f(mnum, item, sub);
break;
case MENU_EDIT:
if (edit_items[item].call_f)
edit_items[item].call_f(mnum, item, sub);
break;
case MENU_SETUP:
domenu_setup(item, sub);
break;
#if 0
case MENU_NATIONAL:
domenu_nation(item, sub);
break;
#endif
}
}